#include "HTTP_Server.hpp"

HTTP_Server::HTTP_Server(){
    // 设置服务器的IP地址和端口号
    HttpServerAddr.sin_family = PF_INET;
    HttpServerAddr.sin_port = htons(SERVER_PORT);
    HttpServerAddr.sin_addr.s_addr = inet_addr(SERVER_IP);
    listen_fd = 0;
}

void HTTP_Server::Init(){
    cout << "Init HTTP Server....."<<endl;
    cout << "Init Socket....." << endl;

    //  初始化套接字
    listen_fd = socket(PF_INET, SOCK_STREAM, 0);
    if(listen_fd < 0){
        perror("socket create error");
        exit(-1);
    }
    int bind_result = bind(listen_fd, (struct sockaddr *)&HttpServerAddr, sizeof(HttpServerAddr));
    if ( bind_result < 0)
    {
        perror("bind error");
        exit(-1);
    }
    if(listen(listen_fd, 5) < 0){
        perror("listen error");
        exit(-1);
    }

    // 初始化Epoll
    epoll.create();

    // 将服务器的监听socketfd加入到epoll的监听事件当中
    HTTP_Request *request = new HTTP_Request(listen_fd, epoll.get_epoll_fd());
    epoll.add_fd(request, listen_fd, true);

    // 初始化线程池
    threadpool.Init();

    // 初始化定时器队列
    timer_queue.init_timer_queue();

    cout << "HTTP Server Initialization Complete." << endl;
    cout << "HTTP Server Infomation:" << endl;
    cout << "HTTP Server IP:               " << SERVER_IP << endl;
    cout << "HTTP Server Port:             " << SERVER_PORT << endl;
    cout << "HTTP Server Listen Socket Fd: " << listen_fd << endl;
}

void HTTP_Server::Run(){
    Init();
    cout << "HTTP Server Start...." << endl;
    while (1)
    {
        // 获取最近且未删除的timer距离现在的时间。（等待时间）
        int timeout = timer_queue.find_timer();

        // 这里应该将上面得到的时间传入到timeout
        // 当timeout不在是-1时，epoll_wait不会永久堵塞，如果timeout到时的时候就会直接返回
        // 这个时候应该将超时的连接全部关闭。
        epoll.wait_for_event(timeout);

        // 处理已经超时的请求
        // 这里的超时有两种情况
        // 1）处理request的时候发生了错误
        // 接到request时会惰性删除掉对应的timer，处理完之后会重新加入定时队列
        // 但是如果处理request的时候发生了问题，则不会重新加入。这时候超时，需要在这里处理
        // 2）epoll_wait等待了timeout长的时间但是并没有接收到请求，则认为其超时了，虽然其并没有被惰性删除
        timer_queue.handle_expire_timers();

        epoll.handle_event(timer_queue, listen_fd, threadpool, get_request);
    }
}

/*******************************************
 * 线程池的回调函数
 * 负责解析HTTP请求，发送HTTP响应。
*******************************************/
void HTTP_Server::get_request(void *arg){

    HTTP_Request *request = (HTTP_Request *)arg;
    request->get_timer_node()->del_timer();

    int len = request->HTTP_Reccive_Request();
    if(len <= 0){
        request->close_connection();
        delete request;
        return;
    }
    request->HTTP_Parse_Request();

    /* 
        如果是长连接则并不需要关闭TCP连接，
        并且需要将定时节点重新加入,
        由于前面设置了EPOLLONESHOT，所以每次处理完一次连接后都需要重新在epoll时间表中进行注册
    */ 
    if(request->get_alive()){
        HTTP_Server::timer_queue.add_timer(request);
        HTTP_Server::epoll.mod_fd(request);
    }

    /*
        如果非长连接，则关闭TCP连接，并释放掉请求节点，
    */
    else{
        //cout << "Close client" << request->get_client_fd() << endl;
        request->close_connection();
        delete request;
    }
}